library ImageStruct/*v1.0
*************************************************************************************
*
*   ImageStruct enables struct syntax with images.
*   Useful when you have advanced systems which relies on images.
* 
************************************************************************************
*
*   */ uses /*
* 
*       */ ImageTools    /* [url]http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/[/url]
*       */ optional ARGB /* [url]http://www.wc3c.net/showthread.php?t=101858[/url]
*
************************************************************************************
*
*       struct Image extends array
* 
*           Creator/Destructor:
*               static method create takes string path, real sX, real sY, real pX, real pY, real pZ, integer imageTypeIndex, boolean render returns thistype
*                   - Allocates a new Image instance and calls NewImage.
*                   - Automatically renders the image if "render" is true.
*
*               method destroy takes nothing returns nothing
*
*           Methods which automatically re-draw the image:
*
*               method setSizeX takes real size returns nothing
*               method setSizeY takes real size returns nothing
*               method setFile  takes string filepath returns nothing
*               method setImageType takes integer index returns nothing
*              
*           Methods which automatically re-locate the image:
*      
*               method setPosX takes real x returns nothing
*               method setPosY takes real y returns nothing
*               method setPosZ takes real z returns nothing
*               method setPosition takes real x, real y, real z returns nothing
*               method wrap takes boolean flag returns nothing
*                   - binds the image to the ground no matter what posZ is set.
*
*           Additional render options, automatically re-renders the image.
*
*               method renderForAll takes nothing returns nothing
*                   - renders this image for all players.
*
*               method renderForForce takes force whichForce returns nothing
*                   - renders this image for all players in force whichForce.
*
*               method renderLocalPlayer takes player whichPlayer returns nothing
*                   - renders this image only for a local client ( whichPlayer ).
*
*           Colorize images with ARGB:
*               method setColor takes ARGB paint returns nothing
*
*           Colorize images without ARGB:
*               method setColor takes integer Red, integer Green, integer Blue, integer Alpha returns nothing
*
*           Extra:
*
*               method setPositionEx takes real x, real y, real z returns nothing
*                   - Here x, y, z define the center of the image, similar to
*                     the coordinates which you use in other handle type
*                     i.e. CreateUnit(p, id, x, y , 0)
*
*           Readonly fields:
*
*               readonly image   img
*               readonly string  file
*               readonly real    sizeX
*               readonly real    sizeY
*               readonly real    posX
*               readonly real    posY
*               readonly real    posZ
*               readonly boolean show
*               readonly integer imageType
*               readonly boolean wrapped
*               readonly integer green
*               readonly integer red
*               readonly integer blue
*               readonly integer alpha
*
*   3. Configuration
*       If you are using library ARGB, you should define a default color.
*  
*/
    globals
        constant integer DEFAULT_IMAGE_COLOR = 0xFFFFFFFF
    endglobals
   
//! textmacro IMAGE_TOOLS_IMPORT_STRUCT_CODE

    private keyword IMAGE_TOOLS_M
    struct Image extends array   
        implement IMAGE_TOOLS_M
   
        readonly image   img
        readonly string  file
        readonly real    sizeX
        readonly real    sizeY
        readonly real    posX
        readonly real    posY
        readonly real    posZ
        readonly boolean show
        readonly integer imageType
        readonly boolean wrapped
        private  force   frc
        private  player  user

        private method paint takes nothing returns nothing
            static if LIBRARY_ARGB then
                call SetImageColor(img, red, green, blue, alpha)
            else
                if hasColor then
                    call SetImageColor(img, red, green, blue, alpha)
                endif
            endif
        endmethod
       
        static if LIBRARY_ARGB then
            readonly ARGB tint
       
            method operator red takes nothing returns integer
                return tint.red
            endmethod
            method operator green takes nothing returns integer
                return tint.green
            endmethod
            method operator blue takes nothing returns integer
                return tint.blue
            endmethod
            method operator alpha takes nothing returns integer
                return tint.alpha
            endmethod
            method operator color takes nothing returns ARGB
                return tint
            endmethod
            method setColor takes ARGB cool returns nothing
                set tint = cool
                call paint()
            endmethod
        else
            readonly integer green
            readonly integer red
            readonly integer blue
            readonly integer alpha
            private boolean hasColor
            method setColor takes integer Red, integer Green, integer Blue, integer Alpha returns nothing
                set alpha    = A/*  */lpha
                set red      = R/*  */ed
                set green    = G/*  */reen
                set blue     = B/*  */lue
                set hasColor = true
                call paint()
            endmethod
        endif
       
        private method draw takes nothing returns nothing
            if (img != null) then
                call ReleaseImage(img)
                set img = null
            endif
            set img = NewImage(file, sizeX, sizeY, posX, posY, posZ, imageType)
            call SetImageConstantHeight(img, not wrapped, posZ)
            call paint()
            if (user == null) and (frc == null) then
                call SetImageRenderAlways(img, show)
            elseif (user != null) then
                call SetImageRenderAlways(img, (show) and (GetLocalPlayer() == user))
            else
                call SetImageRenderAlways(img, (show) and IsPlayerInForce(GetLocalPlayer(), frc))
            endif
        endmethod
       
        method wrap takes boolean flag returns nothing
            set  wrapped = flag
            call SetImageConstantHeight(img, not wrapped, posZ)
        endmethod
       
        method renderForAll takes nothing returns nothing
            set user = null
            set frc  = null
            call draw()
        endmethod
       
        method renderLocalPlayer takes player whichPlayer returns nothing
            set user = whichPlayer
            call draw()
        endmethod
       
        method renderForForce takes force whichForce returns nothing
            set frc = whichForce
            call draw()
        endmethod

        method setSizeX takes real value returns nothing
            set sizeX = value
            call draw()
        endmethod
       
        method setSizeY takes real value returns nothing
            set sizeY = value
            call draw()
        endmethod
       
        method setFile takes string filepath returns nothing
            set file = filepath
            call draw()
        endmethod
       
        method setPosX takes real amount returns nothing
            set posX = amount
            call SetImagePosition(img, amount, posY, posZ)
        endmethod
       
        method setPosY takes real amount returns nothing
            set posY = amount
            call SetImagePosition(img, posX, amount, posZ)
        endmethod
       
        method setPosZ takes real value returns nothing
            set posZ = value
            call SetImageConstantHeight(img, true, value)
        endmethod
       
        method setPositionEx takes real x, real y, real z returns nothing
            set posX = x - sizeX*.5
            set posY = y - sizeY*.5
            set posZ = z
            call SetImagePosition(img, posX, posY, posZ)
            call SetImageConstantHeight(img, not wrapped, z)
        endmethod
       
        method setPosition takes real x, real y, real z returns nothing
            set posX = x
            set posY = y
            set posZ = z
            call SetImagePosition(img, posX, posY, posZ)
            call SetImageConstantHeight(img, not wrapped, z)
        endmethod
       
        // Checks for errors in NewImage
        method setImageType takes integer i returns nothing
            set imageType = i
            call SetImageType(img, i)
            call draw()
        endmethod
       
        static method create takes string path, real sX, real sY, real pX, real pY, real pZ, integer imageTypeIndex, boolean render returns thistype
      local thistype this = thistype.allocate()
            set file      = path
            set show      = render
            set sizeX     = sX
            set sizeY     = sY
            set posX      = pX
            set posY      = pY
            set posZ      = pZ
            set wrapped   = false
            set imageType = imageTypeIndex
            static if not LIBRARY_ARGB then
                set hasColor = false
            else
                set tint  = DEFAULT_IMAGE_COLOR
            endif
            call draw()
            return this
        endmethod

        method destroy takes nothing returns nothing
            if (img != null) then
                call ReleaseImage(img)
                set img = null
            endif
            set user = null
            set frc  = null
        endmethod
       
    endstruct   
   
    private module IMAGE_TOOLS_M
        private static integer array recycler
        static method allocate takes nothing returns thistype
            local thistype this = recycler[0]
            debug if (this == 8192) then
                debug call DebugMsg("Overflow - Requires an allocation module above 8910!")
                debug return 0
            debug endif
            if (0 == recycler[this]) then
                set recycler[0] = this + 1
            else
                set recycler[0] = recycler[this]
            endif
            debug set recycler[this] = -1
            return this
        endmethod
   
        method deallocate takes nothing returns nothing
            debug if (recycler[this] != -1) then
                debug call DebugMsg("Attempted To Deallocate Null Instance. ( Double Free )")
            debug endif
            set recycler[this] = recycler[0]
            set recycler[0] = this
        endmethod
       
        private static method onInit takes nothing returns nothing
            set recycler[0] = 1
        endmethod
    endmodule
//! endtextmacro

endlibrary